﻿namespace NetFx.SMIL.Definitions
{
  using System;
  using System.Text;
  using System.Collections;
  using System.Collections.Generic;

  using System.Reflection;
  using System.Reflection.Emit;
  using System.Runtime.InteropServices;

  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;
  using System.Security;
  using System.Security.Permissions;

  using NetFx.MSIL;
  using NetFx.SMIL.References;

  public abstract class MemberDef : ReflectDef
  {
    #region Statics
    public static MemberDef of(MemberInfo memberInfo)
    {
      if (memberInfo != null)
      {
        if (memberInfo is FieldInfo)
        {
          return FieldDef.of(memberInfo as FieldInfo);
        }
        else if (memberInfo is Type && ((Type)memberInfo).IsEnum)
        {
          return EnumDef.of(memberInfo as Type);
        }
        else if (memberInfo is EventInfo)
        {
          return EventDef.of(memberInfo as EventInfo);
        }
        else if (memberInfo is MethodBase)
        {
          return MethodDef.of(memberInfo as MethodBase);
        }
        else if (memberInfo is PropertyInfo)
        {
          return PropertyDef.of(memberInfo as PropertyInfo);
        }
        else if (memberInfo is Type)
        {
          return TypeDef.of(memberInfo as Type);
        }
      }
      return null;
    }
    #endregion
    #region Fields
    protected TypeRef declaringType = null;
    protected TypeRef reflectedType = null;
    protected ModuleRef module = null;
    protected int metadataToken = 0;
    #endregion
    #region Properties
    public virtual TypeRef DeclaringType
    {
      get 
      {
        return this.declaringType;
      }
      set
      {
        this.declaringType = value;
      }
    }
    public virtual TypeRef ReflectedType
    {
      get 
      { 
        return this.reflectedType ;
      }
      set
      {
        this.reflectedType = value;
      }
    }
    public virtual ModuleRef Module
    {
      get
      {
        return this.module;
      }
      set
      {
        this.module = value;
      }
    }
    public virtual int MetadataToken
    {
      get
      {
        return this.metadataToken;
      }
    }
    #endregion
    #region Constructors
    public MemberDef(string name) : base(name) { }
    public MemberDef(MemberInfo memberInfo) : base(String.Empty ) 
    {
      this.OnReflecting(memberInfo);
    }
    #endregion
    #region Methods
    #region Helpers
    protected override AnyGenerator OnCompleting(AnyGenerator generator)
    {
      return base.OnCompleting(generator);
    }
    protected override AnyGenerator OnDefining(AnyGenerator container)
    {
      return base.OnDefining(container);
    }
    protected override ReflectDef OnReflecting(object source)
    {
      if (source is MemberInfo)
      {
        MemberInfo mi = source as MemberInfo;
        this.name = mi.Name;
        this.declaringType = TypeRef.of(mi.DeclaringType);
        this.reflectedType = TypeRef.of(mi.ReflectedType);
        this.module = ModuleRef.of(mi.Module);
        this.metadataToken = mi.MetadataToken;
      }
      return base.OnReflecting(source);
    }
    protected virtual void ReloadParameters(ParameterInfo[] parameters, IList defs)
    {
      if (parameters != null && defs != null)
      {
        defs.Clear();

        foreach (ParameterInfo pi in parameters)
        {
          defs.Add(ParameterDef.of(pi));
        }
      }
    }
    protected virtual void ReloadVariables(LocalVariableInfo[] variables,IList defs)
    {
      if (variables != null && defs != null)
      {
        defs.Clear();

        foreach (LocalVariableInfo variable in variables)
        {
          defs.Add(VariableDef.of(variable));
        }
      }
    }
    protected override void OnBreakingReference()
    {
      this.Break(this.DeclaringType);
      this.Break(this.ReflectedType);
      this.Break(this.Module);
      base.OnBreakingReference();
    }
    #endregion
    #endregion
  }
}
